﻿using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.LogDomain;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.Enums;
using Zocono.WCS.Infrastructure.ApllicationDto.WCSTaskDto;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 托盘运输中途扫码询问目标位置或PLC把目标位置丢失
    /// </summary>
    public class ScanPalletMoveService : IPlanarGeneralPlcActionProcessService
    {

        private readonly ISnowflake _Snowflake;
        private readonly ILogUtil _LogUtil;
        private readonly IRedisHelper _IRedisHelper;
        private readonly IPlcConnectionPool _PlcConnectionPool;
        private readonly IWorkTaskInfoRepository _WorkTaskInfoRepository;
        private readonly IPlcWriteDbInfoRepository _PlcWriteDbInfoRepository;
        private readonly ITaskRouteDetailRecordInfoRepository _TaskRouteDetailRecordInfoRepository;
        private readonly IPlcConnectionStateInfoRepository _IPlcConnectionStateInfoRepository;
        private readonly IRunLogInfoService _IRunLogInfoService;

        public ScanPalletMoveService(IRedisHelper iRedisHelper, ILogUtil logUtil,
            IPlcConnectionPool plcConnectionPool,
            IWorkTaskInfoRepository workTaskInfoRepository,
            IPlcWriteDbInfoRepository plcWriteDbInfoRepository,
            ISnowflake snowflake,
            ITaskRouteDetailRecordInfoRepository taskRouteDetailRecordInfoRepository,
            IPlcConnectionStateInfoRepository plcConnectionStateInfoRepository
             , IRunLogInfoService runLogInfoService)
        {
            _LogUtil = logUtil;
            _IRedisHelper = iRedisHelper;
            _PlcConnectionPool = plcConnectionPool;
            _WorkTaskInfoRepository = workTaskInfoRepository;
            _PlcWriteDbInfoRepository = plcWriteDbInfoRepository;
            _Snowflake = snowflake;
            _TaskRouteDetailRecordInfoRepository = taskRouteDetailRecordInfoRepository;
            _IPlcConnectionStateInfoRepository = plcConnectionStateInfoRepository;
            _IRunLogInfoService = runLogInfoService;
        }


        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage, EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {
            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;
            plcMessage.PalletBarcode = plcMessage.PalletBarcode.Trim();
            //var plcStateBo = plcStateMassge as PlcOnLineStateBO;//Plc在线离线报文 没有设备信息
            RunLogInfo runLogInfo = new RunLogInfo();
            runLogInfo.ContainerBarcode = plcMessage.PalletBarcode;
            runLogInfo.EquipmentCode = plcMessage.EquipmentCode;
            runLogInfo.RunType = " 托盘运输中途扫码询问目标位置";

            runLogInfo.RunLog = " 托盘运输中途扫码询问目标位置任务开始";
            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);



            var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
            var writeConfig = await _PlcWriteDbInfoRepository.GetFirstAsync(it => it.EquipmentCode == plcMessage.EquipmentCode && it.ObjectType == objectType);
            if (writeConfig == null)
            {
                //runLogInfo.RunLog = $" 获取PLC写入配置失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"托盘运输中途扫码询问目标位置：托盘【{plcMessage.PalletBarcode}】在设备【{plcMessage.EquipmentCode}】托盘运输中途扫码询问目标位置获取PLC写入配置失败！请检查写DB配置！");
                return;
            }

            var plcCon = _PlcConnectionPool.S7GetWritePlcConnection(writeConfig.PlcConnectionId);
            if (plcCon == null)
            {
                //runLogInfo.RunLog = $"获取连接({writeBo.PlcConnectionID})失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"托盘运输中途扫码询问目标位置：托盘【{plcMessage.PalletBarcode}】在设备【{plcMessage.EquipmentCode}】托盘运输中途扫码询问目标位置：plc连接池无数据");
                return;
            }
            //1. 验证plc是否在线
            var plcIPStates = await _IPlcConnectionStateInfoRepository.GetFirstAsync(l => l.PlcConnectionID == plcMessage.PlcConnectionID && l.Connected == true);
            if (plcIPStates == null)
            {
                //runLogInfo.RunLog = $" {plcCon.IP}plc已离线";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"托盘运输中途扫码询问目标位置：托盘【{plcMessage.PalletBarcode}】在设备【{plcMessage.EquipmentCode}】托盘运输中途扫码询问目标位置：请求分配失败：{plcCon.IP}:plc已离线");
                return;
            }
            //if (plcMessage.AlrmCode != 0)
            //{
            //    runLogInfo.RunLog = $"报警,报警代码：{plcMessage.AlrmCode}";
            //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    return;
            //}

            //plc报文什么握手类型则回什么握手类型
            PlanarGeneralWriteWcsAction writeBo = new PlanarGeneralWriteWcsAction(
                writeConfig.PlcConnectionId,
                writeConfig.ID,
                writeConfig.DbCode,
                writeConfig.DbStart,
                objectType,
                writeConfig.EquipmentCode.ToInt32(),
                plcMessage.ActionType,
                0,//运输托盘只给目标节点，中间节点不予理会
                0,
                "",
                plcMessage.PalletType,
                0);


            //校验plc信息是否有托盘码
            if (string.IsNullOrEmpty(plcMessage.PalletBarcode) || plcMessage.PalletBarcode.Length != 10)
            {
                writeBo.AlrmCode = 102;
                writeBo.ActionType = 99;
                var flag = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            #region 托盘进入打包台线体上报
            //托盘进入到打包台线体，脱离环线通知WMS 
            if (plcMessage.ActionType == 60)
            {
                Zocono.WCS.WMSApiDomain.WebApi.HeaderResult<bool> flag = await WCSMessageWithWMSApi.TrayOutRingLineAsync(plcMessage.PalletBarcode, plcMessage.EquipmentCode);
                if (flag.IsSucceed)
                {
                    writeBo.ActionType = 61;
                    var writeBl = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    if (writeBl)
                    {
                        runLogInfo.RunLog = $"此托盘【{plcMessage.PalletBarcode}】进入打包台线体上报成功,写入PLC报文成功，报文内容：{JsonConvert.SerializeObject(writeBo)}";
                        await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    }
                }
                else
                {
                    //runLogInfo.RunLog = $"此托盘【{plcMessage.PalletBarcode}】进入打包台线体上报失败";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    writeBo.ActionType = 99;
                    writeBo.AlrmCode = 54;
                    var writeBl = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                }
                return;
            }
            #endregion

            //此托盘任务是否存在
            var exp = Expressionable.Create<WorkTaskInfo>();

            exp.AndIF(true, l => l.PalletCode == plcMessage.PalletBarcode && l.TaskState == EnumTaskState.Executing);
            var task = await _WorkTaskInfoRepository.GetFirstAsync(exp.ToExpression());

            if (task == null)
            {
                //runLogInfo.RunLog = $" 此托盘({plcMessage.PalletBarcode})没有在执行的任务";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                writeBo.ActionType = 99;
                writeBo.AlrmCode = 7;
                var writeBl = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            //托盘类型
            switch (task.PalletCode.Substring(1, 1))
            {
                case "A":
                    writeBo.PalletType = 2;
                    break;
                case "B":
                    writeBo.PalletType = 1;
                    break;
                case "C":
                    writeBo.PalletType = 3;
                    break;
            }

            #region 托盘经过环线未分配到打包台线体，重新回滚回130067
            //托盘环线未进入打包台线体，从130187出来继续环线 通知WMS修改任务 
            if (plcMessage.ActionType == 65)
            {
                WmsTaskInfoDto tempTask = null;
                try
                {
                    //回滚 拿到回滚任务
                    WMSApiDomain.WebApi.HeaderResult<WmsTaskInfoDto> res = await WCSMessageWithWMSApi.WCSGetRollbackTaskAsync(plcMessage.PalletBarcode, plcMessage.EquipmentCode);
                    if (res.IsSucceed)
                    {
                        tempTask = res.Result;
                    }
                    else
                    {
                        var msg = res.Message;
                        runLogInfo.RunLog = $"向Wms请求任务失败:{msg}";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

                        if (msg.Contains("没有配置工位信息"))
                            writeBo.AlrmCode = 20;
                        else if(msg.Contains("NG分选机出口扫码位置流程报错"))
                            writeBo.AlrmCode = 21;
                        else if (msg.Contains("不存在业务类型数据"))
                            writeBo.AlrmCode = 22;
                        else if (msg.Contains("扫码位置流程报错"))
                            writeBo.AlrmCode = 23;
                        else if (msg.Contains("投入口无法查询对应的流程"))
                            writeBo.AlrmCode = 24;
                        else if (msg.Contains("没有绑定流程参数"))
                            writeBo.AlrmCode = 25;
                        else if (msg.Contains("节点数据配置异常"))
                            writeBo.AlrmCode = 26;
                        else if (msg.Contains("未配置巷道分配关联数据"))
                            writeBo.AlrmCode = 27;
                        else if (msg.Contains("未配置巷道分配关联明细数据"))
                            writeBo.AlrmCode = 28;
                        else if (msg.Contains("未配置巷道分组指针"))
                            writeBo.AlrmCode = 29;
                        else if (msg.Contains("没有可用巷道"))
                            writeBo.AlrmCode = 30;
                        else if (msg.Contains("不存在流程配置参数数据"))
                            writeBo.AlrmCode = 43;
                        else if (msg.Contains("未解绑"))
                            writeBo.AlrmCode = 41;
                        else if (msg.Contains("不存在托盘数据"))
                            writeBo.AlrmCode = 44;
                        else if (msg.Contains("流程节点应为待处理状态！请查看OCV数据是否上传"))
                            writeBo.AlrmCode = 47;
                        else if (msg.Contains("请调整对应流程节点状态为待处理状态"))
                            writeBo.AlrmCode = 48;
                        else if (msg.Contains("绑定的流程配置有误！，OCV没测试排出"))
                            writeBo.AlrmCode = 49;
                        else if (msg.Contains("无法获取对应电池类型配置的流程参数"))
                            writeBo.AlrmCode = 50;
                        else if (msg.Contains("任务到达上限"))
                            writeBo.AlrmCode = 51;
                        else if (msg.Contains("没有上传数据"))
                            writeBo.AlrmCode = 52;
                        else
                            writeBo.AlrmCode = 105;
                        if (writeBo.AlrmCode == 0)
                            writeBo.AlrmCode = 3;

                        writeBo.ActionType = 99;
                        var flag = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                        _LogUtil.Error($"托盘经过环线未分配到打包台线体：托盘【{plcMessage.PalletBarcode}】在设备【{plcMessage.EquipmentCode}】请求分配失败：ex{runLogInfo.RunLog}");
                        return;
                    }
                }
                catch (Exception ex)
                {
                    if (ex.Message.Contains("at") && ex.Message.Contains("System.Exception:"))
                    {
                        var msg = ex.Message.Split("at").First().Split("System.Exception:");
                        runLogInfo.RunLog = $"向Wms请求任务失败:{msg[1]}";
                    }
                    else
                    {
                        var msg = ex.Message.Length > 150 ? ex.Message.Substring(0, 100) : ex.Message;
                        runLogInfo.RunLog = $"向Wms请求任务失败:{msg}";
                    }
                    writeBo.AlrmCode = 106;
                    writeBo.ActionType = 99;
                    var flag = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                    _LogUtil.Error($"托盘经过环线未分配到打包台线体：托盘【{plcMessage.PalletBarcode}】在设备【{plcMessage.EquipmentCode}】请求分配失败：ex{runLogInfo.RunLog}");
                    return;
                }
                if (tempTask != null)
                {
                    task.WmsFromPosition = tempTask.StartPosition;
                    task.WmsToPosition = tempTask.EndPosition;
                    task.WmsFromStation = tempTask.FromStation;
                    task.WmsToStation = tempTask.ToStation;

                    //获取配置路径信息
                    var routeConfigExp = Expressionable.Create<RouteInfo>();
                    routeConfigExp.AndIF(true, (a) => a.FromStation == task.WmsFromStation && a.ToStation == task.WmsToStation);
                    var routeInfo = await _WorkTaskInfoRepository.AsSugarClient()
                        .Queryable<RouteInfo>()
                        .Where(routeConfigExp.ToExpression())
                        .Select((a) => new RouteInfo()
                        {
                            ID = a.ID,
                            FromStation = a.FromStation,
                            ToStation = a.ToStation,
                        }).FirstAsync();
                    if (routeInfo == null)
                    {
                        runLogInfo.RunLog = $"起始工位{task.WmsFromStation}目标工位{task.WmsToStation}获取工位失败";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        _LogUtil.Error($"托盘经过环线未分配到打包台线体：托盘【{plcMessage.PalletBarcode}】在设备【{plcMessage.EquipmentCode}】请求分配失败：ex{runLogInfo.RunLog}");
                        writeBo.AlrmCode = 108;
                        writeBo.ActionType = 99;
                        var flag = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                        return;
                    }

                    //路径详情信息
                    var routeDetailConfigExp = Expressionable.Create<RouteDetailInfo>();
                    routeDetailConfigExp.AndIF(true, (a) => a.RouteID == routeInfo.ID && a.IsStart);
                    var routeDetailInfo = await _WorkTaskInfoRepository.AsSugarClient()
                        .Queryable<RouteDetailInfo>()
                        .Where(routeDetailConfigExp.ToExpression())
                        .Select((a) => new
                        {
                            a.ID,
                            a.RouteID,
                            a.FromCargo,
                            a.ToCargo,
                            a.DispatchType,
                            a.FromEquipment,
                            a.ToEquipment,

                        }).FirstAsync();

                    if (routeDetailInfo == null)
                    {
                        runLogInfo.RunLog = $"巷道路径详情配置信息起始工位{task.WmsFromStation} 目标工位 {task.WmsToStation}获取设备路径失败";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                        _LogUtil.Error($"托盘经过环线未分配到打包台线体：托盘【{plcMessage.PalletBarcode}】在设备【{plcMessage.EquipmentCode}】请求分配失败：ex{runLogInfo.RunLog}");
                        writeBo.AlrmCode = 109;
                        writeBo.ActionType = 99;
                        var flag = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                        return;
                    }

                    task.CurrentToEquipment = routeDetailInfo.ToEquipment;


                    task.CurrentFromCargo = routeDetailInfo.FromCargo;
                    task.CurrentToCargo = routeDetailInfo.ToCargo;
                    task.RouteID = routeDetailInfo.RouteID;
                    task.CurrentRounteDetailID = routeDetailInfo.ID;
                    task.CurrentDispatchType = routeDetailInfo.DispatchType;
                    //起始设备位 
                    task.CurrentFromEquipment = task.WmsFromPosition; //WMS 作业实际起点设备
                                                                      // workTaskInfo.CurrentToEquipment = routeDetailInfo.ToEquipment;
                    task.CurrentDetailTaskState = EnumDetailTaskState.Executing;
                    //task.CurrentCreateTime = DateTime.Now;
                    task.CurrentUpdateTime = DateTime.Now;

                    //task.SaveTime = DateTime.Now;
                    task.UpdateTime = DateTime.Now;

                    //更新任务信息主要只是起始目标位置和路径ID和路径详情ID
                    await _WorkTaskInfoRepository.UpdateAsync(task);
                }
            }

            #endregion
            //记录到子任务表
            //TaskRouteDetailRecordInfo routeDetail = new TaskRouteDetailRecordInfo();
            //routeDetail.ID = _Snowflake.GetId();
            //routeDetail.TaskID = task.ID;
            //routeDetail.RouteDetailID = task.CurrentRounteDetailID;
            //routeDetail.DetailTaskState = EnumDetailTaskState.Finish;
            //routeDetail.DispatchType = task.CurrentDispatchType;
            //routeDetail.FromEquipment = plcMessage.EquipmentCode;
            //routeDetail.FromCargo = plcMessage.EquipmentCode;
            //routeDetail.ToEquipment = task.CurrentToEquipment;
            //routeDetail.ToCargo = task.CurrentToCargo;//?
            //routeDetail.CreateTime = DateTime.Now;
            //routeDetail.UpdateTime = DateTime.Now;


            //try
            //{
            //   //var res= await _TaskRouteDetailRecordInfoRepository.InsertAsync(routeDetail);
            //    if (res)
            //    {

            //        runLogInfo.RunLog = $"插入子任务成功";
            //        await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    }
            //    else
            //    {

            //        runLogInfo.RunLog = $"插入子任务失败";
            //        await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    }
            //}
            //catch (Exception ex)
            //{
            //    runLogInfo.RunLog = $"插入子任务出错：{ex.Message}";
            //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    return;
            //}


            //task.CurrentFromEquipment = plcMessage.EquipmentCode;
            //task.CurrentFromCargo = plcMessage.EquipmentCode;
            //task.CurrentUpdateTime = DateTime.Now;
            //task.CurrentUpdateTime = DateTime.Now;

            //try
            //{
            //    var res = await _WorkTaskInfoRepository.UpdateAsync(task);
            //    if (res)
            //    {

            //        runLogInfo.RunLog = $"更新任务成功";
            //        await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    }
            //    else
            //    {

            //        runLogInfo.RunLog = $"更新任务失败";
            //        await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    }
            //}
            //catch (Exception ex)
            //{
            //    runLogInfo.RunLog = $"更新任务出错：{ex.Message}";
            //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    return;
            //}

            try
            {
                writeBo.PalletBarcode = task.PalletCode;
                writeBo.TaskCode = task.TaskCode;
                writeBo.ToEquipmentCode = task.CurrentToEquipment.ToInt32();
                //如果是一楼环线回滚 回复66确认
                if (plcMessage.ActionType == 65)
                {
                    writeBo.ActionType = 66;
                }
                var res = await plcCon.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                if (!res)
                {
                    //runLogInfo.RunLog = $"请求分配重复:写入正常报文报文失败";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

                    _LogUtil.Error($"环线回滚：托盘【{plcMessage.PalletBarcode}】环线回滚，PLC设备【{plcMessage.EquipmentCode}】写入PLC失败！");
                    return;
                }
                else
                {
                    runLogInfo.RunLog = $"环线回滚：托盘【{plcMessage.PalletBarcode}】环线回滚，PLC设备【{plcMessage.EquipmentCode}】写入PLC成功！写入报文：{JsonConvert.SerializeObject(writeBo)}";
                    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

                }
            }
            catch (Exception ex)
            {
                runLogInfo.RunLog = $"写入PLC报错 ex={ex.Message}";

                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"环线回滚：托盘【{plcMessage.PalletBarcode}】在设备【{plcMessage.EquipmentCode}，{runLogInfo.RunLog}");
                return;
            }

        }

    }
}
